import { Component, OnInit, AfterViewInit, HostListener, Input, Output, ViewChild, ElementRef, Renderer2, EventEmitter } from '@angular/core';
import { Store, MemoizedSelector } from '@ngrx/store';
import { map } from 'rxjs/operators';

import { MapState, foldingSelector, SetBasemaps, SetGrid, SetLayers, SetMeasure, SetResourceTree, SetSpaticlFiltering, FoldingAction, FoldingState, SetUpload } from '../../store';
import { Folding } from '../../models';

@Component({
  selector: 'ege-folding-container',
  templateUrl: './folding-container.component.html',
  styleUrls: ['./folding-container.component.scss']
})
export class FoldingContainerComponent implements OnInit, AfterViewInit {

  private _options: Folding = {
    title: '默认设置',
    imgSrc: null,
    icon: null,
    type: null,
    visible: false,
    iconType: 'icon',
    clickHide: false,
    clickDocumentHide: true,
    style: 'rectangle',
    button: false,
    deactiveOther: true,
    deactiveByOther: true
  };

  @Output() visibleChange: EventEmitter<boolean> = new EventEmitter();
  @ViewChild('folding') folding: ElementRef;
  @ViewChild('content') content: ElementRef;
  
  @Input() 
  set options(options: Folding) {
    this._options = { ...this.options, ...options };
  }

  get options(): Folding {
    return this._options;
  }

  @HostListener('window:resize', ['$event'])
  onWindowResize(event): void {
    this.setContentPosition();
  }

  @HostListener('document: click', ['$event'])
  onClickDocument(event): void {
    if(this.options.clickDocumentHide && this.options.visible) {
      this.hideContent();
    }
  }

  constructor(
    private renderer: Renderer2,
    private mapStore: Store<MapState>
  ) { }

  ngOnInit() {
    const action = this.action(this.options);
    const selector = this.selector(this.options);
    action && this.mapStore.dispatch(action);
    this.setContentPosition();
    selector && this.mapStore.select(selector).subscribe((folding: Folding) => {
      this._options = folding;
    });
  }

  ngAfterViewInit(): void {
    this.setContentPosition();
  }

  action(payload: Folding): FoldingAction {
    switch(payload.type) {
      case 'BASEMAPS': {
        return new SetBasemaps(payload);
      }
      case 'LAYERS': {
        return new SetLayers(payload);
      }
      case 'SPATICLFILTERING': {
        return new SetSpaticlFiltering(payload);
      }
      case 'MEASURE': {
        return new SetMeasure(payload);
      }
      case 'GRID': {
        return new SetGrid(payload);
      }
      case 'RESOURCETREE': {
        return new SetResourceTree(payload);
      }
      case 'UPLOAD': {
        return new SetUpload(payload);
      }
      default: {
        return null;
      }
    }
  }

  selector(payload: Folding): any {
    switch(payload.type) {
      case 'BASEMAPS': {
        return foldingSelector.getFoldingBasemaps;
      }
      case 'LAYERS': {
        return foldingSelector.getFoldingLayers;
      }
      case 'SPATICLFILTERING': {
        return foldingSelector.getFoldingSpaticlFiltering;
      }
      case 'MEASURE': {
        return foldingSelector.getFoldingMeasure;        
      }
      case 'GRID': {
        return foldingSelector.getFoldingGrid;
      }
      case 'RESOURCETREE': {
        return foldingSelector.getFoldingResourceTree;
      }
      case 'UPLOAD': {
        return foldingSelector.getFoldingUpload;
      }
      default: {
        return null;
      }
    }
  }

  setContentPosition(): void {
    if(!this.options.button && this.content) {
      const mapElement: any = document.querySelector('.map-container');
      const arrowElement: any = this.content.nativeElement.querySelector('.folding-content-arrow');
      const mapHeight: number = mapElement ? mapElement.offsetHeight : 0;
      const contentHeight: number = this.content.nativeElement.offsetHeight;
      const offsetTop: number = this.offsetTop(this.folding, 'map-container') - 15;
      const offsetBottom: number = mapHeight - (offsetTop + 40) - 15;
      let top: number = 0;
      if(offsetTop > (contentHeight - 40) / 2 && offsetBottom > (contentHeight - 40) / 2) {
        top = (contentHeight - 40) / 2 * -1;
      } else if(offsetTop > (contentHeight - 40) / 2 && offsetBottom < (contentHeight - 40) / 2) {
        top = (contentHeight - offsetBottom - 40) * -1;
      } else {
        top = offsetTop * -1;
      }
      this.renderer.setStyle(arrowElement, 'top', `${top * -1 + 20}px`);
      this.renderer.setStyle(this.content.nativeElement, 'top', `${top}px`);
    }
  }

  offsetTop(self: ElementRef, targetClass: string): number {
    let ele = self.nativeElement;
    let offsetTop: number = 0;
    const regExp = new RegExp(`(${targetClass})+`);
    while(ele && !(ele instanceof Document) && !regExp.test(ele.className)) {
      offsetTop+=ele.offsetTop;
      ele = ele.offsetParent;
    }
    return offsetTop;
  }

  hideContent(): void {
    this.options = { ...this.options , visible: false };
    this.visibleChange.emit(this.options.visible);

    const action = this.action(this.options);
    action && this.mapStore.dispatch(action);
  }

  showContent(): void {
    this.options = {...this.options , visible: true };
    this.visibleChange.emit(this.options.visible);

    const action = this.action(this.options);
    action && this.mapStore.dispatch(action);
  }

  onClickButton(e): void {
    e.stopPropagation();
    if(!this.options.visible) {
      this.showContent();
    } else {
      this.hideContent();
    }
  }

  onClickContent(e): void {
    e.stopPropagation();
    if(this.options.clickHide) {
      this.hideContent();
    }
  }



}
